#include <mysql/mysql.h>
#include <chrono> // 存活设置时间
#include <string>
#include <queue>
#include <memory>

#include "../comm/log.hpp"
#include "sqlconn.hpp"
#include "LockGuard.hpp"

namespace ns_sqlconnpool
{

    static const int default_sqlconn_num = 3;

    // template <typename T>
    class SqlConnPool
    {
        static SqlConnPool *_instance;
        static pthread_mutex_t sig_lock;

        pthread_mutex_t _mutex;
        pthread_cond_t _cond;

        size_t Max_Capacity;
        std::queue<SqlConn *> queue; // 连接队列

        std::string ip;
        uint16_t port;
        std::string user;
        std::string password;
        std::string database;

    private:
        // 创建连接
        SqlConn *Create_conn()
        {
            SqlConn *con = new SqlConn();
            con->connect(ip, port, user, password, database);
            return con;
        }

    public:
        SqlConnPool(const SqlConnPool &th) = delete;
        const SqlConnPool operator=(const SqlConnPool &th) = delete;


        SqlConnPool(const std::string &_ip, const uint16_t _port, const std::string &_user, const std::string &_password, const std::string &_database,const int MaxCapacity = default_sqlconn_num) 
        : Max_Capacity(MaxCapacity),ip(_ip),port(_port),user(_user),password(_password),database(_database)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);

            for (int i = 0; i < Max_Capacity; i++)
            {
                SqlConn* conn = Create_conn();
                if(conn!=nullptr)
                queue.push(conn);
            }

            ns_log::lg.LogMessage(ns_log::Info,"当前连接池有 %d 个连接",(int)queue.size());
        }

        ~SqlConnPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

        std::shared_ptr<SqlConn> Get_Conn()
        {
            SqlConn *conn;
            {
                LockGuard lockguard(&sig_lock);

                conn = queue.front();
                queue.pop();
            }

            std::shared_ptr<SqlConn> conn_ptr(conn, [&](SqlConn *conn)
                                              {
            {
                LockGuard lockguard(&sig_lock);
                queue.push(conn);

            } });

            return conn_ptr;
        }

        static SqlConnPool *GetInstance(const std::string &ip, const uint16_t port, const std::string &user, const std::string &password, const std::string &database) // 饿汉模式
        {
           
            if (_instance == nullptr)
            {
                LockGuard lockguard(&sig_lock);
                ns_log::lg.LogMessage(ns_log::Info, "创建单例成功!");
                if (_instance == nullptr)
                {
                    return new SqlConnPool(ip, port, user, password, database);
                }
            }
            return _instance;
        }
    };

    SqlConnPool * SqlConnPool::_instance = nullptr;

    pthread_mutex_t SqlConnPool::sig_lock = PTHREAD_MUTEX_INITIALIZER;

}